﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Text;
using System.Text.Json;

namespace Asion.RPC
{
    public class RpcRegistry
    {

        /// <summary>
        /// api interface to rpc config client name
        /// </summary>
        private static ConcurrentDictionary<string, string> api_rpc_relations = new ConcurrentDictionary<string, string>();

        private static ConcurrentDictionary<string, RpcConfiguration> rpc_cofigurations = new ConcurrentDictionary<string, RpcConfiguration>();

        private static string defualt_config_file_name = "dms.json";

       
        /// <summary>
        /// 配置端口
        /// </summary>
        public static void ConfigureHostDefaults(string filePath)
        {
            //配置文件方式
            //1.指定具体文件
            //2.默认加载具体文件地址
            string basePath = AppDomain.CurrentDomain.BaseDirectory;
            string relativeFilePath = Path.Combine(basePath, filePath);
            if (!File.Exists(relativeFilePath))
            {
                throw new Exception("rpc dms json is not exist");
            }
            string json = File.ReadAllText(filePath);
            var configs = JsonSerializer.Deserialize<List<RpcConfiguration>>(json);
            if (configs == null)
            {
                throw new Exception("rpc config is null");
            }
            foreach (var item in configs)
            {
                if (!rpc_cofigurations.ContainsKey(item.AppName))
                {
                    rpc_cofigurations.TryAdd(item.AppName, item);
                }
            }

            //注册的时候扫描这个项目中的所有接口

            var interfaces = GetRpcApiInterface();
            foreach (var item in interfaces)
            {
                //获取rpc的 attribute
                var rpcClientAttribute = item.GetCustomAttribute<RpcClientAttribute>();
                if (rpcClientAttribute != null)
                {
                    //查询这个配置在配置文件中是否存在
                    if (!rpc_cofigurations.ContainsKey(rpcClientAttribute.Name))
                    {
                        throw new Exception($"rpc {rpcClientAttribute.Name} is not setting");
                    }
                    if (!api_rpc_relations.ContainsKey(item.FullName))
                    {
                        api_rpc_relations.TryAdd(item.FullName, rpcClientAttribute.Name);
                    }

                }

            }

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="interfaceFullName"></param>
        /// <returns></returns>
        public static string GetRpcDefaultApi(string interfaceFullName)
        {
            if (!api_rpc_relations.ContainsKey(interfaceFullName))
            {
                throw new Exception($"{interfaceFullName} relation is not found");
            }
            var configName = api_rpc_relations[interfaceFullName];
            if (!rpc_cofigurations.ContainsKey(configName))
            {
                throw new Exception($"{configName} config is not found");
            }
            var config = rpc_cofigurations[configName];

            return config.DefaultApi;
        }



        /// <summary>
        /// Init扫描
        /// </summary>
        public static List<Type> GetRpcApiInterface()
        {
            var assemblys = AppDomain.CurrentDomain.GetAssemblies();

            //var assemblys=new List<Assembly>(){Assembly.Load("Asion.RPC.WebApi.Client") };
            var interfaceType = typeof(IRpcApi);
            var reponse = new List<Type>();
            foreach (var assembly in assemblys)
            {
                // 获取所有实现该接口的非抽象类
                var implementations = assembly.GetTypes()
                    .Where(t => interfaceType.IsAssignableFrom(t) && t.IsInterface)
                    .ToList();
                reponse.AddRange(implementations);
            }
            return reponse;
        }
    }
}
